/*
    io_com.h - definitions for io communication driver 
	
	
	Author: Benedikt Niedermayr (2013)
	

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

	This source code is also a result of my bachelor thesis.

*/

#ifndef _IO_COM_H
#define _IO_COM_H

//#include "../global.h"
#include <linux/timer.h>
#include <linux/ktime.h>      /* Für Timer Funktionen              */
#include <linux/fs.h>         /* Enthält Flags zur Filebearbeitung */
#include <linux/device.h> 
#include <linux/cdev.h>       /* Unterstützung für /sys/class      */
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h> /* Platform Treiber */
#include <linux/gpio.h>
#include <linux/workqueue.h>

#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <mach/irqs.h>
#include <asm/uaccess.h>      /*enthält die Prototypen für die Funktionen
                               *copy_to_user und copy_from_user
			      			   */
#include <linux/pagemap.h> 
#include <linux/i2c.h>

/* Simulate Flag
 * If this flag is set to 1, the io_core driver will only simulate the
 * presence of the io controller.
 * The dummy-Funktion create_debug_answer_string() will create the answer
 * for each reuqest of the Linux Host.
 * If set to an other value than 1, the answer string will be requested directly
 * from the io controller via the communication interface (i2c or usb-serial).
 */
#define SIMULATE 1

//// actuall status == NOT SUPPORTED!! 



/* Debug Flag 
 * Specifies wether the io driver should give you some debug printk output.
 * (1 -> Debugging active , 0-> Debugging inactive)
 */
#define DEBUG 1 

/*
 * Interrupt Line flags
 * Specifies wether IRQ Line is used or not.
 */
#define IRQ_LINE_CON	0x01
#define IRQ_LINE_DISCON	0x02
#define IRQ_LINE 		IRQ_LINE_CON
/* specify the connected irq line gpio.
 * This is architecture specific!
 */
#define IO_IRQ_GPIO	11

#define MAX_DATA_LEN	1023
#define MAX_COMMAND_ID	99
#define MAX_IOCBS		1023




#define MAJOR_IO_CORE		240
#define MAJOR_IO_I2C		241
#define MAJOR_IO_GPIO		242
#define MAJOR_IO_COM_I2C	243
#define MAJOR_IO_COM_SUSB	244
	
/* sync or async mode flags
 */
#define ASYNC	0
#define SYNC	1

/* package flags
 * Identify the type of a package
 * (e.g. FFUNC is function flag, FSYS is system flag )
 */
#define FFUNC	'F'
#define FSYS	'S'
#define FANSW	'A'
#define FIRQ	'I'


/*
 * Direction of Inferace 
 * In(read) or out(write)
 */ 
#define DIR_IN	'0'
#define DIR_OUT '1'
#define DIR_DM	'2'	//Dont matter direction character

/* Function interface characters. 
 * A function command is joined together of INTERFACE and DIRECTION
 * charakter of the specific userspace driver
 */
#define IO_I2C	'd'
#define IO_SPI	'a'
#define IO_PWM	'g'
#define IO_ADC	'f'
#define IO_DAC	'e'
#define IO_GPIO	'b'
#define IO_UART	'c'


/*
 * System commands init/deinit
 */
#define INIT_SPI0	"a0"
#define INIT_SPI1	"a2"
#define INIT_I2C0	"b0"
#define INIT_UART0	"c0"
#define INIT_UART1	"c3"
#define INIT_PWM	"d0"
#define INIT_GPIO	"e0"
#define INIT_ADC	"f0"
#define INIT_DAC	"g0"
#define INIT_TIMER	"h0"

#define DEINIT_SPI0	"a1"
#define DEINIT_SPI1	"a3"
#define DEINIT_I2C0	"b1"
#define DEINIT_UART0 "c1"
#define DEINIT_UART1 "c4"
#define DEINIT_PWM	"d1"
#define DEINIT_GPIO	"e1"
#define DEINIT_ADC	"f1"
#define DEINIT_DAC	"g1"
#define DEINIT_TIMER "h1"





/*
 * Controll characters
 */
#define NEW_CMD	'x'				//"\r"
#define END_OF_FRAME 'y'			//"\n"

/*
 * Interrupt codes
 */
#define IRQ_CODE_I2C	1 
#define IRQ_CODE_SPI	2
#define IRQ_CODE_TIMER	3
#define IRQ_CODE_CMD_ANSW	4	//Interrupt for receiving slave handshake
#define IRQ_CODE_GPIO1	10
#define IRQ_CODE_GPIO2	(IRQ_CODE_GPIO1 + 1)
#define IRQ_CODE_GPIO3	(IRQ_CODE_GPIO1 + 2) 
#define IRQ_CODE_GPIO4	(IRQ_CODE_GPIO1 + 3)
#define IRQ_CODE_GPIO5	(IRQ_CODE_GPIO1 + 4)
#define IRQ_CODE_GPIO6	(IRQ_CODE_GPIO1 + 5)
#define IRQ_CODE_GPIO7	(IRQ_CODE_GPIO1 + 6)
#define IRQ_CODE_GPIO8	(IRQ_CODE_GPIO1 + 7)
#define IRQ_CODE_GPIO9	(IRQ_CODE_GPIO1 + 8)
#define IRQ_CODE_GPIO10	(IRQ_CODE_GPIO1 + 9)
#define IRQ_CODE_GPIO11	(IRQ_CODE_GPIO1 + 10)
#define IRQ_CODE_GPIO12	(IRQ_CODE_GPIO1 + 11)
#define IRQ_CODE_GPIO13	(IRQ_CODE_GPIO1 + 12)
#define IRQ_CODE_GPIO14	(IRQ_CODE_GPIO1 + 13)
#define IRQ_CODE_GPIO15	(IRQ_CODE_GPIO1 + 14)
#define IRQ_CODE_GPIO16	(IRQ_CODE_GPIO1 + 15)
#define IRQ_CODE_GPIO17	(IRQ_CODE_GPIO1 + 16)
#define IRQ_CODE_GPIO18	(IRQ_CODE_GPIO1 + 17)
/* Specify the irq trigger type between linux host 
 * an io controller
 */
#define IO_IRQ_TRIGGER IRQF_TRIGGER_FALLING


/*
 * testing!!!!!!!!!!!!!!!!!!!!!
 */
#define CONST_LEN_STRING 5   //0-5


/* params - Struct representing a full parameter string
 * This also represents a list with each of it consisting
 * the data of one parameter
 */
struct params {
	int nr;
	int len_val;		// length of parameter Value
	int len_const;		// length of string before parameter payload beginns
	char *val;
	char *string;
	struct list_head list;
};




/* answ_cmd - Struct representing a full command answer
 * and corresponding answer_command string.
 * This also represents a list of single chained answers
 * from the i/o processor 
 */
struct answ_cmd {
		int cmd_id;
		int answ_len;			//Länge des Antwort Payloads
		char interface;
		char direction;
		char cmd_flag;	
		char *answer_payload;	// Nutzdaten der Antwort
		struct list_head list;	//Listenkopf
};




/* cmd - Struct representing a full command
 * and corresponding command string
 */
struct cmd {
		int cmd_id;				//Identifikationsnummer 
		int sys_cmd;			// Wird bei System Kommandos verwendet
		char interface;  		// Auslösendes Userspace Interface
		char direction;  		// In oder out
		char cmd_flag; 			// Art des Kommandos (Sys, Funktion, IRQ oder Answer) 
		struct params	root;	// Speichern der Parameter über Liste
		struct params	*ptr;

		char *params_string;	 // Speichern der Parameter über String
		int   params_string_len; // Länge des Parameter Strings (wichtig für memcpy)
		int payload_len;		 // Länge des Userspace payloads (write Zugriff)
		int cmd_len;			 //Lägne des kompletten cmd_strings (ohne NEW_CMD Zeichen!!)
		char *cmd_string;		 // cmd String für dieses Element (Beginn immer mit '/r') 

		struct answ_cmd *corresp;		// Pointer auf zugehörige Antwort
		void   *user_buf;				// Pointer auf virtuelle Adresse des Userspace buffers, welcher vom zugehörigen Userpace Prozess übergeben wird.
										// Hier wird die Antwort des I/O Prozessors hinein kopiert.
		struct page *page;
		unsigned long offset;
		struct list_head list;			// Listenkopf für Anfrage Liste (Kommando Liste)
		
};









struct io_com;
struct io_i2c;
struct io_gpio;

/* This struct will be overgiven
 * in each function of io_com driver.
 * It will be initialized one time.
 */
struct io_com {

	/* device specific elements 
     */
	struct cdev *io_core_object;
	struct class *io_class;		
	struct device *io_core_dev;
	struct device *io_core_user_dev;
	dev_t io_core_number;



	/* global default send/receive buffer
	 * used to send/receive directly to/from
	 * Hardware Buffers 
     */  
	char *def_buff_send;
	int send_buff_len;
	char *def_buff_recv;
	int recv_buff_len;
	char *handshake_request_string;
	
	char debug_answer_test_string[1024];		// This string is temporary used for Debug purpose
	
	int iocb_cnt;								// Zähler für Anzahl der aktiven asynchronen Aufträge 

	int (*io_handler_send)(struct io_com *, char *, int );
	int (*io_handler_recv)(struct io_com *, char *, int );

	/* pointer to different io extension modules */	
	struct io_i2c *io_i2c_pointer;
	//struct io_spi *io_spi_pointer;
	//struct io_adc *io_adc_pointer;
	//struct io_pwm *io_pwm_pointer;
	//struct io_timer *io_timer_pointer;
	struct io_gpio *io_gpio_pointer;

	/* different io_com interface definitions */
	
	/* USB-serial io_com driver	*/
	struct file *tty_file;		

	/* I²C io_com driver */	
	struct i2c_client *client;		
	
	/* pointer to specific hw_driver 
	 * (USB,Serial-USB,I²C) 
	 *--> will be converted to specific data type! 
	 */
	void *hw_driver;


	/* actuall interrupt code */
	int irq_code;		

	/* interrupt occured flag */
	int int_oc;

	/* global lock (security among all instances) */
	struct mutex cnt_lock, async_lock, sync_func_lock, add_cmd_lock , iocb_lock;

	/* list rootpointers and required variables */
	/* rootpointer for command list
	 * this get initialized only 
	 * one time
	 */	
	struct cmd cmd_root;		
	struct cmd *cmd_ptr;

	
	/* rootpointer for answer list */
	struct answ_cmd answ_root;	
	struct answ_cmd *answ_ptr;

	struct list_head list;	//Listenkopf
	
	//struct list_head *pos, *qu;

};




/* global variables */
extern struct io_com *global_pointer;
extern struct kiocb *iocb_kick[MAX_IOCBS]; 	// globale iocb Liste (enthält Pointer auf aktive Aufträge)
extern struct workqueue_struct *wq_global;
extern struct work_struct gpio_bottom_half;
extern struct work_struct i2c_bottom_half;

/* extern functions(SYMBOLS) from io_com.c */
extern int io_core_recv(struct io_com *, char *, int);
extern int io_core_send(struct io_com *, char *, int);
extern int io_add_cmd(struct io_com *, const char *);
extern int add_param_to_list(int , char *, struct cmd * , int);
extern int create_params_string(struct cmd *);
extern int create_func_package (int , char, char, struct cmd *);
extern int create_sys_package (int , char *, struct cmd *);
extern int add_cmd_to_list(struct cmd *, struct io_com *);
extern int convert_recvbuff_to_list(struct io_com *);
extern int create_send_buff(struct io_com *);
extern int alloc_requ_and_answ(struct io_com *);
extern int sync(struct io_com *);
extern char *new_char(int);

#endif /* _IO_COM_H */




